<template>
  <div :class="{focus, err: errMsg || msg}"
       class="input-box">
    <i :class="`icon iconfont icon-${icon}`"/>
    <div class="input">
      <input v-model="inputValue"
             :placeholder="placeholder"
             :type="type"
             @focusin="focus = true"
             @focusout="handleFocusOut"
             @input="judge(true);emit('input')"/>
    </div>
    <div class="right">
      <slot/>
    </div>
    <div v-if="msg"
         class="err-msg">
      {{ msg }}
    </div>
    <div v-else
         v-show="errMsg"
         class="err-msg">
      {{ errMsg }}
    </div>
  </div>
</template>

<script lang="ts"
        setup>
import type {Rule} from '@/assets/utils/validate'
import {computed, ref, toRefs} from 'vue'

let emit = defineEmits<{
  (e: 'update:modelValue', v: any): void
  (e: 'focusout', v: any): void
  (e: 'input'): void
}>()

let props = withDefaults(defineProps<{
  modelValue?: any,
  placeholder?: string,
  type?: string,
  icon?: string,
  msg?: string,
  rules?: Rule[]
}>(), {
  type: 'text',
  msg: '',
  placeholder: ''
})

let {msg} = toRefs(props)

defineExpose({
  judge
})

let inputValue = computed({
  get() {
    return props.modelValue
  },
  set(v: any) {
    emit('update:modelValue', v)
  }
})
let errMsg = ref<string>('')
let focus = ref<boolean>(false)
let handleFocusOut = () => {
  focus.value = false
  emit('focusout', inputValue.value)
  judge()
}

function judge(input: boolean = false): boolean {
  if (!props.rules?.length) return true
  for (let i in props.rules)
    if (!props.rules[i].rule.test(inputValue.value)) {
      // 如果为input调用，则不改变errMsg值，只在验证成功时清除
      if (!input) errMsg.value = props.rules[i].msg
      return false
    }
  errMsg.value = ''
  return true
}
</script>

<style lang="less"
       scoped>
.input-box {
  width: 320px;
  height: 50px;
  display: flex;
  border: 1px solid #e4e4e4;
  position: relative;

  &.focus {
    border: 1px solid @xtxColor;
  }

  &.err {
    border: 1px solid @priceColor;
  }

  i {
    width: 50px;
    height: 50px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #999999;
  }

  .input {
    flex: 1;

    input {
      width: 100%;
      height: 100%;
      padding-right: 10px;
    }
  }

  .err-msg {
    position: absolute;
    white-space: nowrap;
    line-height: 50px;
    margin-left: 20px;
    left: 100%;
    color: @priceColor;
  }
}
</style>